#include "Date.h"
Date::Date(int year, int month, int day)
{
    _year = year;
    _month = month;
    _day = day;
    if (_year < 1 ||
        _month < 1 || month > 12 ||
        _day < 1 || _day > GetMonthDay(_year, _month))
    {
        // assert(false);
        // perror 一般是调用了系统的库函数，比如fopen，malloc 出错后才用
        Print();
        cout << "日期非法" << endl;
    }
}

void Date::Print()
{
    cout << _year << "/" << _month << "/" << _day << endl;
}

bool Date::operator==(const Date &y)
{
    return _year == y._year // 比较当前对象的_year和y对象的_year
           && _month == y._month && _day == y._day;
}
// 为何有y._year???
// 当你定义一个类的成员函数，并且这个函数需要访问另一个同类型对象的成员时，你会使用参数来传递这个对象。在你提供的Date类的operator == 函数中，const Date & y是一个对Date类型对象的常量引用，
// 它作为函数的参数，允许函数访问y对象的成员变量。

// d1 != d2
bool Date::operator!=(const Date &y)
{
    return !(*this == y);
}
//*this：在类的成员函数中，this是一个指向当前对象的指针。* this就是对这个指针的解引用，它表示当前对象本身。
//	通过使用* this，我们可以访问当前对象的所有成员变量和成员函数。
// y：是operator != 函数的参数，它是一个对Date类型对象的常量引用。在函数内部，我们可以直接访问y对象的所有公有（public）成员。
//
//* this == y这部分代码会调用先前定义的operator == 函数，比较当前对象（即 * this所引用的对象）和参数y所引用的对象是否相等。如果它们相等， * this == y的结果为true，否则为false。

bool Date::operator>(const Date &y)
{
    if (_year > y._day)
    {
        return true;
    }
    else if (_year == y._day && _month > y._month)
    {
        return true;
    }
    else if (_year == y._day && _month == y._month && _day > y._day)
    {
        return true;
    }
}

bool Date::operator>=(const Date &y)
{
    return *this > y || *this == y; // 大于等于 就是 大于或者等于
}

bool Date::operator<(const Date &y)
{
    return !(*this >= y);
}

bool Date::operator<=(const Date &y)
{
    return !(*this > y);
}

int Date::GetMonthDay(int year, int month)
{
    assert(year >= 1 && month >= 1 & month <= 12);
    int monthArray[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
        return 29;
    return monthArray[month];
}

// d1-d2
int Date::operator-(const Date &d)
{
    // 假设左大右小
    int flag = 1;
    Date max = *this;
    Date min = d;

    // 假设错了的话，就是左小右大;
    if (*this < d) // 这里调用了bool operator<(const Date& y);
    {
        max = d;
        min = *this;
        flag = -1;
    }
    int n = 0;
    while (min != max)
    {
        ++min; // 调用了 operator++()。operator++() 的实现调用了 operator+=(int)
        // operator+=(1) 会根据上述逻辑自动更新 min 的日期（天、月、年）。
        ++n;
    }
    return n * flag;
}

Date &Date::operator+=(int day)
{
    // 处理加的天数是负数的情况
    if (day < 0)
    {
        return *this -= (-day);
    }
    else
    {
        _day += day;
        while (_day > GetMonthDay(_year, _month))
        {
            _day -= GetMonthDay(_year, _month);
            // 假如_day=36,那个月有31天，则进一个月，
            ++_month;
            if (_month == 13)
            {
                _year++;
                _month = 1; // 这里不要弄错了！
            }
        }
    }
}

Date Date::operator+(int day)
{
    Date tmp(*this);
    tmp += day;
    // 当你使用tmp += day; 这样的表达式时，你实际上是在调用operator += 成员函数。这是因为 += 是一个复合赋值操作符，
    // 它结合了加法和赋值两个操作。当你使用 += 时，编译器会寻找一个匹配的operator += 成员函数，并调用它。

    return tmp;
}
// 为什么不是Date& Date::operator+(int day) ？
// 这个函数返回的是Date的一个临时对象（即值返回），而不是对现有对象的引用。这意味着当你调用这个函数时，你会得到一个全新的、独立的Date对象，它包含了计算后的结果。
// 不使用Date& Date::operator+(int day)的原因主要有以下几点：
//
// 语义正确性：operator + 通常用于执行加法运算并返回一个新的结果对象，而不是修改现有的对象。如果你返回一个引用，那么返回的可能是局部对象的引用，这是未定义行为，因为局部对象在函数返回后会被销毁。
//
// 避免别名：返回引用可能会引入别名问题。如果operator + 返回一个引用，那么调用者可能会错误地认为这个引用指向了原始对象或某个持久对象，而实际上它可能指向一个即将被销毁的临时对象。
//+
// 可链式调用：如果operator + 返回引用，则可能会导致链式调用时出现问题。例如，date1 + day1 + day2这样的表达式，如果operator + 返回引用，那么第二个 + 操作符实际上是在一个临时对象上调用，这同样会导致未定义行为。
//
// 移动语义：即使Date类支持移动语义（通过实现移动构造函数和移动赋值操作符），返回引用也不是个好主意，因为这会阻止编译器使用返回值优化（RVO）来避免不必要的拷贝或移动。
//
// 一致性：对于大多数内置类型和标准库中的类型，operator + 都是返回值的。保持一致的行为有助于减少混淆和提高代码的可读性。

Date &Date::operator-=(int day)
{
    if (day < 0)
    {
        return *this += (-day); // 减 负的天数 就是加上
    }
    _day -= day;
    while (_day <= 0)
    {
        --_month;
        if (_month == 0)
        {
            --_year;
            _month = 12;
        }
        _day += GetMonthDay(_year, _month);
    }
    return *this;
}
Date Date::operator-(int day)
{
    Date tmp(*this);
    tmp -= day;
    return tmp;
}

//   ++d1
Date &Date::operator++()
{
    *this += 1;
    return *this;
}
//   d1++  后置要保存一个变量再返回，多一次拷贝，效率不如前置++
// C++使用了一个特殊的技巧：重载后置递增操作符时接受一个不使用的整数参数。这个参数在函数定义中通常被忽略，但在语法上区分了前置和后置版本。
Date Date::operator++(int) // (int i ) 一般这里都不写形参，写了也没什么意义
{
    Date tmp(*this);
    *this += 1;
    return tmp;
}

//--d;
Date &Date::operator--()
{
    *this -= 1;
    return *this;
}

// d--;
Date Date::operator--(int)
{
    Date tmp(*this);
    *this -= 1;
    return tmp;
}

// ————————————————总结:多复用！！！